package cn.netdisk.tinynetdisk.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.netdisk.tinynetdisk.common.entity.BaseFileContent;
import cn.netdisk.tinynetdisk.entity.ChunkFile;
import cn.netdisk.tinynetdisk.entity.FileInfo;
import cn.netdisk.tinynetdisk.service.INetDiskService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class NetDiskServiceImpl implements INetDiskService {
    /**
     * 锁对象
     */
    private final Object lock = new Object();

    /**
     * 锁对象2
     */
    private final Object lock2 = new Object();

    @Override
    public List<FileInfo> getFileInfo(String baseDir) {
        File file = new File(baseDir);
        if (!file.exists()) {
            return new ArrayList<>();
        } else {
            File[] files = file.listFiles();
            if (files == null || files.length == 0) {
                return new ArrayList<>();
            }
            List<FileInfo> fileInfos = new ArrayList<>(files.length);
            for (File item : files) {
                FileInfo fileInfo = new FileInfo();
                if (item.isDirectory()) {
                    fileInfo.setFileName(item.getName());
                    fileInfo.setParentDir(baseDir);
                    fileInfo.setType(0);
                    fileInfo.setUpdateTime(DateUtil.format(new Date(item.lastModified()), "yyyy-MM-dd"));
                    fileInfo.setUpdateTimeAll(DateUtil.format(new Date(item.lastModified()), "yyyy-MM-dd HH:mm:ss"));
                    fileInfo.setUpdate(item.lastModified());
                } else {
                    fileInfo.setFileName(item.getName());
                    fileInfo.setParentDir(baseDir);
                    fileInfo.setType(1);
                    fileInfo.setFileSize(item.length());
                    fileInfo.setUpdateTime(DateUtil.format(new Date(item.lastModified()), "yyyy-MM-dd"));
                    fileInfo.setUpdateTimeAll(DateUtil.format(new Date(item.lastModified()), "yyyy-MM-dd HH:mm:ss"));
                    fileInfo.setUpdate(item.lastModified());
                }
                fileInfos.add(fileInfo);
            }
            return fileInfos.stream().sorted(Comparator.comparingLong(FileInfo::getUpdate).reversed()).collect(Collectors.toList());

        }
    }

    @Override
    public boolean createDir(String baseDir) {
        File file = new File(baseDir);
        if (!file.exists()) {
            return file.mkdir();
        }
        return false;
    }

    @Override
    public boolean createFile(String baseDir) throws IOException {
        File file = new File(baseDir);
        if (!file.exists()) {
            return file.createNewFile();
        }
        return false;
    }

    @Override
    public BaseFileContent readFile(String baseDir) {
        File file = new File(baseDir);
        if (!file.exists()) {
            return null;
        }
        if (file.isDirectory()) {
            return null;
        }
        String content = FileUtil.readString(file, Charset.defaultCharset());
        BaseFileContent baseFileContent = new BaseFileContent();
        baseFileContent.setContent(content);
        return baseFileContent;
    }

    @Override
    public boolean writeFile(BaseFileContent baseFileContent) {
        File file = new File(baseFileContent.getSuffix());
        if (!file.exists()) {
            return false;
        }
        if (file.isDirectory()) {
            return false;
        }
        try {
            FileUtil.writeString(baseFileContent.getContent(), file, Charset.defaultCharset());
            return true;
        } catch (Exception e) {
            return false;
        }

    }

    @Override
    public boolean deleteFile(String baseDir) {
        File file = new File(baseDir);
        if (!file.exists()) {
            return false;
        }
        //强制清除无引用的对象
//        System.gc();
//        System.runFinalization();
        //System.out.println(baseDir);
        return FileUtil.del(baseDir);
    }

    @Override
    public boolean renameFile(String baseDir, String oldName, String newName) {
        File oldFile = new File(baseDir + "/" + oldName);
        if (!oldFile.exists()) {
            return false;
        }
        return oldFile.renameTo(new File(baseDir + "/" + newName));
    }

    @Override
    public boolean uploadFile(ChunkFile chunkFile, MultipartFile file) throws IOException {
        String baseUri = chunkFile.getSuffix();
        if (chunkFile.getRelativePath().contains("/")) {
            String[] files = chunkFile.getRelativePath().split("/");
            StringBuilder appendPath = new StringBuilder();
            for (int i = 0; i < files.length - 1; i++) {
                appendPath.append("/" + files[i]);
                //  System.out.println(baseUri + appendPath.toString());
                createDir(baseUri + appendPath.toString());
            }
            baseUri = baseUri + "/" + chunkFile.getRelativePath().substring(0, chunkFile.getRelativePath().lastIndexOf("/"));
        }

        File sourceFile = new File(baseUri + "/" + chunkFile.getFilename() + "_" + chunkFile.getChunkNumber());
        if (!sourceFile.exists()) {
            sourceFile.createNewFile();
        }
        file.transferTo(sourceFile);
        boolean f = false;
        synchronized (lock) {
            if (getChunkFiles(chunkFile, baseUri).size() == chunkFile.getTotalChunks()) {
                f = mergeFiles(chunkFile, baseUri);
            }

        }
        return f;
    }

    @Override
    public boolean mergeFiles(ChunkFile chunkFile, String baseDir) throws IOException {
        List<File> files = getChunkFiles(chunkFile, baseDir);
        // System.out.println("真实文件:"+baseDir);
        File file = new File(baseDir + "/" + chunkFile.getFilename());
        if (!file.exists()) {
            file.createNewFile();
        } else {
            file.delete();
        }
        //long start=System.currentTimeMillis();
        for (File item : files) {
            byte[] bytes = FileUtil.readBytes(item);
            FileUtil.writeBytes(bytes, file, 0, bytes.length, true);
            item.delete();
        }
        //System.out.println("耗时:"+(System.currentTimeMillis()-start));
        return chunkFile.getTotalSize() == file.length();
    }

    @Override
    public List<File> getChunkFiles(ChunkFile chunkFile, String baseDir) {
        File file = new File(baseDir);
        if (!file.exists()) {
            return new ArrayList<>();
        } else {
            Map<Integer, File> map = new HashMap<>();
            List<File> list = new ArrayList<>();
            File[] files = file.listFiles();
            if (files == null || files.length == 0) {
                return new ArrayList<>();
            }
            for (File item : files) {
                if (item.getName().contains(chunkFile.getFilename() + "_")) {
                    String[] arr = item.getName().split("_");
                    map.put(Integer.parseInt(arr[arr.length - 1]), item);
                }
            }
            Set<Integer> integers = map.keySet();
            List<Integer> sortList = CollUtil.sort(integers, Comparator.comparing(Integer::intValue));
            for (Integer num : sortList) {
                list.add(map.get(num));
            }
            return list;
        }

    }


}
